#include "get_video_by_https.h"

// 初始化OpenSSL
void init_openssl() {
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
}

// 清理OpenSSL
void cleanup_openssl() {
    EVP_cleanup();
}

// 创建SSL上下文
static SSL_CTX *create_context() {
    const SSL_METHOD *method;
    SSL_CTX *ctx;

    method = SSLv23_client_method();
    ctx = SSL_CTX_new(method);
    if (!ctx) {
        perror("Unable to create SSL context");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    return ctx;
}

// 建立TCP连接
static int create_tcp_connection(const char *hostname, int port) {
    int sockfd;
    struct hostent *host;
    struct sockaddr_in dest_addr;

    if ((host = gethostbyname(hostname)) == NULL) {
        perror("Cannot resolve hostname");
        exit(EXIT_FAILURE);
    }

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(port);
    dest_addr.sin_addr.s_addr = *(long*)(host->h_addr_list[0]);

    if (connect(sockfd, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) != 0) {
        close(sockfd);
        perror("Connection failed");
        exit(EXIT_FAILURE);
    }

    return sockfd;
}

// 解析URL
static void parse_url(const char *url, char *hostname, char *path) {
    char *protocol = strstr(url, "://");
    const char *host_start;
    const char *path_start;
    
    if (protocol) {
        host_start = protocol + 3; // 跳过 "://"
    } else {
        host_start = url;
    }
    
    path_start = strchr(host_start, '/');
    if (!path_start) {
        strcpy(path, "/");
        strcpy(hostname, host_start);
    } else {
        strncpy(path, path_start, 1024);
        path[1023] = '\0';
        strncpy(hostname, host_start, path_start - host_start);
        hostname[path_start - host_start] = '\0';
    }
}

// 从HTTP头中提取字段
static char* get_header_value(char* headers, const char* field) {
    char* field_start = strstr(headers, field);
    if (!field_start) return NULL;
    
    field_start += strlen(field);
    // 跳过可能的空格和冒号
    while (*field_start == ' ' || *field_start == ':') field_start++;
    
    char* field_end = strchr(field_start, '\r');
    if (!field_end) field_end = strchr(field_start, '\n');
    if (!field_end) return field_start;
    
    // 创建一个临时字符串来返回
    int len = field_end - field_start;
    char* result = (char*)malloc(len + 1);
    if (!result) return NULL;
    
    strncpy(result, field_start, len);
    result[len] = '\0';
    return result;
}

// 下载文件，支持重定向
static void download_file(const char *url, const char *output_file) {
    char current_url[2048];
    strncpy(current_url, url, sizeof(current_url) - 1);
    current_url[sizeof(current_url) - 1] = '\0';
    
    int redirect_count = 0;
    char hostname[256] = {0};
    char path[1024] = {0};
    char request[2048];
    char buffer[BUFFER_SIZE];
    int sockfd;
    SSL *ssl;
    SSL_CTX *ctx;
    int bytes_received;
    int total_bytes = 0;
    int header_parsed = 0;
    FILE *fp;
    int content_length = -1;
    int remaining_bytes = -1;
    char header_buffer[BUFFER_SIZE * 4] = {0};
    int header_buffer_size = 0;
    int status_code = 0;
    char* location = NULL;
    
    while (redirect_count < MAX_REDIRECTS) {
        // 解析URL
        parse_url(current_url, hostname, path);
        
        printf("Connecting to %s...\n", hostname);

        // 初始化OpenSSL
        init_openssl();
        ctx = create_context();

        // 建立TCP连接
        sockfd = create_tcp_connection(hostname, DEFAULT_PORT);

        // 创建SSL连接
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, sockfd);
        if (SSL_connect(ssl) <= 0) {
            ERR_print_errors_fp(stderr);
            exit(EXIT_FAILURE);
        }

        // 构建HTTP请求
        snprintf(request, sizeof(request),
                 "GET %s HTTP/1.1\r\n"
                 "Host: %s\r\n"
                 "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\r\n"
                 "Accept: */*\r\n"
                 "Connection: close\r\n\r\n",
                 path, hostname);

        // 发送HTTP请求
        int bytes_sent = SSL_write(ssl, request, strlen(request));
        if (bytes_sent <= 0) {
            perror("Failed to send HTTP request");
            exit(EXIT_FAILURE);
        }
        printf("Sent HTTP request (%d bytes)\n", bytes_sent);

        // 重置状态变量
        header_parsed = 0;
        total_bytes = 0;
        content_length = -1;
        remaining_bytes = -1;
        memset(header_buffer, 0, sizeof(header_buffer));
        header_buffer_size = 0;
        status_code = 0;
        if (location) {
            free(location);
            location = NULL;
        }

        // 打开输出文件（如果是第一次尝试）
        if (redirect_count == 0) {
            fp = fopen(output_file, "wb");
            if (!fp) {
                perror("Failed to open output file");
                exit(EXIT_FAILURE);
            }
        }

        // 接收响应并写入文件
        while ((bytes_received = SSL_read(ssl, buffer, BUFFER_SIZE)) > 0) {
            // 检查是否已经解析完HTTP头
            if (!header_parsed) {
                // 将接收到的数据添加到头缓冲区
                if (header_buffer_size + bytes_received < sizeof(header_buffer)) {
                    memcpy(header_buffer + header_buffer_size, buffer, bytes_received);
                    header_buffer_size += bytes_received;
                } else {
                    // 头缓冲区溢出，这是一个错误
                    fprintf(stderr, "HTTP header too large\n");
                    exit(EXIT_FAILURE);
                }
                
                // 查找HTTP头结束位置
                char *body_start = strstr(header_buffer, "\r\n\r\n");
                if (body_start) {
                    // 提取状态码
                    char* status_line = header_buffer;
                    while (*status_line && *status_line != ' ') status_line++;
                    if (*status_line) status_line++;
                    status_code = atoi(status_line);
                    printf("HTTP Status: %d\n", status_code);
                    
                    // 检查是否是重定向
                    if (status_code == 301 || status_code == 302) {
                        location = get_header_value(header_buffer, "Location");
                        if (location) {
                            printf("Redirecting to: %s\n", location);
                            strncpy(current_url, location, sizeof(current_url) - 1);
                            current_url[sizeof(current_url) - 1] = '\0';
                            
                            // 清理资源并准备重定向
                            SSL_free(ssl);
                            close(sockfd);
                            SSL_CTX_free(ctx);
                            cleanup_openssl();
                            
                            redirect_count++;
                            break;  // 跳出内部循环，开始新的重定向
                        }
                    }
                    
                    // 打印HTTP头（用于调试）
                    printf("HTTP Headers:\n%.*s\n", (int)(body_start - header_buffer), header_buffer);
                    
                    // 找到HTTP头结束位置
                    body_start += 4; // 跳过 "\r\n\r\n"
                    int header_length = body_start - header_buffer;
                    int body_length = header_buffer_size - header_length;
                    
                    // 查找Content-Length
                    char* content_length_str = get_header_value(header_buffer, "Content-Length");
                    if (content_length_str) {
                        content_length = atoi(content_length_str);
                        remaining_bytes = content_length;
                        printf("Content-Length: %d bytes\n", content_length);
                        free(content_length_str);
                    }
                    
                    // 写入文件体
                    if (body_length > 0) {
                        size_t bytes_written = fwrite(body_start, 1, body_length, fp);
                        if (bytes_written != body_length) {
                            perror("Failed to write to file");
                            exit(EXIT_FAILURE);
                        }
                        total_bytes += body_length;
                        if (remaining_bytes != -1) {
                            remaining_bytes -= body_length;
                        }
                    }
                    
                    header_parsed = 1;
                }
            } else {
                // 直接写入文件体（不添加空字符）
                size_t bytes_written = fwrite(buffer, 1, bytes_received, fp);
                if (bytes_written != bytes_received) {
                    perror("Failed to write to file");
                    exit(EXIT_FAILURE);
                }
                total_bytes += bytes_received;
                if (remaining_bytes != -1) {
                    remaining_bytes -= bytes_received;
                    if (remaining_bytes <= 0) {
                        // 已经下载了Content-Length指定的字节数
                        break;
                    }
                }
            }
        }

        // 如果不是重定向，则退出循环
        if (status_code != 301 && status_code != 302) {
            break;
        }
    }

    if (redirect_count >= MAX_REDIRECTS) {
        fprintf(stderr, "Maximum number of redirects (%d) exceeded\n", MAX_REDIRECTS);
    }

    // 检查SSL_read是否因为错误而返回
    if (bytes_received <= 0) {
        int err = SSL_get_error(ssl, bytes_received);
        if (err == SSL_ERROR_ZERO_RETURN) {
            printf("Connection closed normally\n");
        } else {
            fprintf(stderr, "SSL_read error: %d\n", err);
            ERR_print_errors_fp(stderr);
        }
    }

    printf("Downloaded %d bytes to %s\n", total_bytes, output_file);

    // 清理资源
    fclose(fp);
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);
    cleanup_openssl();
    if (location) free(location);
}

// http://api.xingchenfu.xyz/API/kxcc.php 开心锤锤（竖版）
// http://api.xingchenfu.xyz/API/dongman.php 动漫混剪（横版）
void get_video_by_https(char *url,char *out_file)
{
    download_file(url, out_file);

    return 0;
}
